export class SdkObservable {
  dependencies: any
  subscriptionFactory: any
  observers: Set<any>
  currentData: any
  freshDataCache: any
  changeSubscription: any
  constructor(e, t, o) {
    this.dependencies = e
    this.subscriptionFactory = t
    this.observers = new Set()
    this.currentData = o.create()
    this.freshDataCache = o.create()
  }
  static async create(e, t, o) {
    const n = await e.getDependencies()
    return new SdkObservable(n, t, o)
  }
  getData() {
    return this.currentData.data
  }
  subscribe(e) {
    return (
      this.addObserver(e),
      new (class ObserverSubscription {
        sdkObservable: any
        constructor(e) {
          this.sdkObservable = e
          this.renew()
        }
        renew() {
          this.sdkObservable.addObserver(e)
        }
        cancel() {
          this.sdkObservable.removeObserver(e)
        }
      })(this)
    )
  }
  addObserver(e) {
    if (!this.observers.has(e)) {
      class SdkObservableFacade {
        observable: any
        constructor(e) {
          this.observable = e
        }
        onChanged() {
          this.observable.onChanged()
        }
      }
      this.observers.add(e),
        1 === this.observers.size &&
          (this.currentData.update(...this.dependencies),
          (this.changeSubscription = this.subscriptionFactory.create(new SdkObservableFacade(this), ...this.dependencies))),
        (e.dirty = !0)
    }
  }
  removeObserver(e) {
    0 !== this.observers.size && (this.observers.delete(e), 0 === this.observers.size && this.changeSubscription.cancel())
  }
  onChanged() {
    if ((this.freshDataCache.update(...this.dependencies), !this.currentData.equals(this.freshDataCache))) {
      this.currentData.copy(this.freshDataCache)
      for (const e of this.observers) e.dirty = !0
    }
  }
}
export class AggregateSubscription {
  subs: any[]
  constructor(...e) {
    this.subs = e
  }
  renew() {
    for (const e of this.subs) e.renew()
  }
  cancel() {
    for (const e of this.subs) e.cancel()
  }
}
export class SdkCollection {
  dependencies: any
  subscriptionFactory: any
  observers: Set<unknown>
  currentData: any
  freshData: any
  changeSubscription: any
  constructor(e, t, o) {
    this.dependencies = e
    this.subscriptionFactory = t
    this.observers = new Set()
    this.currentData = o.create()
    this.freshData = o.create()
  }
  static async create(e, t, o) {
    const n = await e.getDependencies()
    return new SdkCollection(n, t, o)
  }
  getData() {
    return this.currentData.data
  }
  observe(e) {
    return (
      this.addObserver(e),
      new (class ObserverSubscription {
        sdkCollection: any
        constructor(e) {
          this.sdkCollection = e
          this.renew()
        }
        renew() {
          this.sdkCollection.addObserver(e)
        }
        cancel() {
          this.sdkCollection.removeObserver(e)
        }
      })(this)
    )
  }
  addObserver(e) {
    class CollectionChangeObserver {
      sdkCollection: any
      constructor(e) {
        this.sdkCollection = e
      }
      onChanged() {
        const { freshData: e, currentData: t, dependencies: o } = this.sdkCollection
        e.update(...o)
        let n = !1
        for (const o in e.data)
          if (t.data.hasOwnProperty(o)) {
            if (!t.isItemEqual(e, o)) for (const t of this.sdkCollection.observers) t.onUpdated(o, e.data[o]), (n = !0)
          } else for (const t of this.sdkCollection.observers) t.onAdded(o, e.data[o]), (n = !0)
        for (const o in t.data) if (!e.data.hasOwnProperty(o)) for (const e of this.sdkCollection.observers) e.onRemoved(o), (n = !0)
        if (n) for (const e of this.sdkCollection.observers) e.onCollectionUpdated()
        const r = t
        this.sdkCollection.currentData = this.sdkCollection.freshData
        this.sdkCollection.freshData = r
      }
    }
    if (!this.observers.has(e)) {
      this.observers.add(e)
      if (1 === this.observers.size) {
        const e = new CollectionChangeObserver(this)
        this.changeSubscription = this.subscriptionFactory.create(e, ...this.dependencies)
        e.onChanged()
      } else for (const t in this.currentData.data) e.onAdded(t, this.currentData.data[t])
    }
  }
  removeObserver(e) {
    0 !== this.observers.size && (this.observers.delete(e), 0 === this.observers.size && (this.changeSubscription.cancel(), this.currentData.clear()))
  }
}
export class DependencyObserverAdaptor {
  dependencyObserver: any
  constructor(e) {
    this.dependencyObserver = e
  }
  notify() {
    this.dependencyObserver.onChanged()
  }
}
